package com.example.my_helper;

import android.Manifest;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextWatcher;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;

import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static android.content.ContentValues.TAG;


public class BluetoothDebuger {

    final static int ON_CONNECT = 0;
    final static int ON_MESSAGE = 1;
    final static int ON_SEND = 2;
    final static int ON_CLOSE = 3;
    final static int ON_ERROR = 4;
    final static int NOT_FOUND = 5;
    final static int NO_PERMISSION = 6;
    final static int CONFIG_ERROR = 7;
    final static int UNSUPPORT = 8;
    final static int CONSOLE_LOG = 9;
    final static int CONSOLE_REFRESH = 10;
    final static int SEND_DATA = 11;
    private static final int REQUEST_ENABLE_BT = 1;

    public MainActivity parent;
    public Handler handler;
    public View bluetooth_view;

    public LinearLayout serial_config_layout, serial_control_layout;
    public Button open_bt, send_bt, pause_bt, clean_bt, kuaijie_bt;
    public ImageButton toggle_bt, send_clean_bt;
    public TextView console_text, recv_count_label, send_count_label, status_label;
    public EditText send_input, auto_send_input, start_index_input;
    public Spinner send_parity_spinner;
    public CheckBox hex_send_check, hex_recv_check, send_newline_check, show_send_check, show_time_check, auto_newline_check;
    public CheckBox auto_send_check, send_parity_check;
    public ScrollView console_scroll;

    SpannableStringBuilder console_buf = new SpannableStringBuilder("");
    @SuppressLint("SimpleDateFormat")
    public SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    final boolean[] flag = {false};
    int config_layout_heigth;
    public boolean console_pause = false;
    public boolean auto_send_flag = false;
    public int recv_count = 0;
    public int send_count = 0;
    static boolean send_input_flag = false;
    public boolean console_lock = false;
    static int send_input_len = 0;
    public ArrayList<KuaijieText> kuaijie_data;
    public ArrayList<MyBluetoothDevice> mybluetoothDevices;
    public ArrayList<BluetoothDevice> bluetoothDevices;
    public BluetoothDeviceAdapter bluetoothDeviceAdapter;
    public BluetoothAdapter.LeScanCallback bleScanCallback;

    private Lock lock = new ReentrantLock();
    public BluetoothDebuger bluetoothDebuger;
    private BluetoothAdapter bluetoothAdapter;
    public MyBluetoothClient myBluetoothClient;

    private BroadcastReceiver BluetoothScanReceiver;

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @SuppressLint("SetTextI18n")
    public BluetoothDebuger(MainActivity parent)
    {
        this.bluetoothDebuger = this;
        this.parent = parent;
        this.bluetooth_view = parent.bluetooth_view;
        if (!MyApp.myDBHelper.isOpen)
            MyApp.myDBHelper.open();
        kuaijie_data = MyApp.myDBHelper.kuaijie_getdata();
        bluetoothDevices = new ArrayList<>();
        mybluetoothDevices = new ArrayList<>();
        bluetoothDeviceAdapter = new BluetoothDeviceAdapter(mybluetoothDevices, parent);

        serial_config_layout = bluetooth_view.findViewById(R.id.bluetooth_config_layout);
        serial_control_layout = bluetooth_view.findViewById(R.id.bluetooth_control_layout);

        console_scroll = bluetooth_view.findViewById(R.id.bluetooth_console_scroll);
        console_text = bluetooth_view.findViewById(R.id.bluetooth_console_text);
        recv_count_label = bluetooth_view.findViewById(R.id.bluetooth_recv_count_label);
        send_count_label = bluetooth_view.findViewById(R.id.bluetooth_send_count_label);
        status_label = bluetooth_view.findViewById(R.id.bluetooth_status_label);
        toggle_bt = bluetooth_view.findViewById(R.id.bluetooth_toggle_bt);
        send_clean_bt = bluetooth_view.findViewById(R.id.bluetooth_send_clean_bt);
        send_input = bluetooth_view.findViewById(R.id.bluetooth_send_input);
        send_bt = bluetooth_view.findViewById(R.id.bluetooth_send_bt);
        open_bt = bluetooth_view.findViewById(R.id.bluetooth_device_bt);
        clean_bt = bluetooth_view.findViewById(R.id.bluetooth_clean_bt);
        pause_bt = bluetooth_view.findViewById(R.id.bluetooth_pause_bt);
        kuaijie_bt = bluetooth_view.findViewById(R.id.bluetooth_kuaijie_bt);
        hex_send_check = bluetooth_view.findViewById(R.id.bluetooth_hex_send_check);
        hex_recv_check = bluetooth_view.findViewById(R.id.bluetooth_hex_recv_check);
        send_newline_check = bluetooth_view.findViewById(R.id.bluetooth_send_newline_check);
        show_send_check = bluetooth_view.findViewById(R.id.bluetooth_show_send_check);
        show_time_check = bluetooth_view.findViewById(R.id.bluetooth_show_time_check);
        auto_newline_check = bluetooth_view.findViewById(R.id.bluetooth_auto_newline_check);
        send_parity_spinner = bluetooth_view.findViewById(R.id.serial_send_parity_spinner);
        auto_send_check = bluetooth_view.findViewById(R.id.bluetooth_auto_send_check);
        auto_send_input = bluetooth_view.findViewById(R.id.bluetooth_auto_send_input);

        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if(bluetoothAdapter == null)
        {
            this.handler.sendEmptyMessage(UNSUPPORT);
        }
        myBluetoothClient = new MyBluetoothClient(parent, handler);

        serial_config_layout.post(new Runnable() {
            @Override
            public void run() {
                config_layout_heigth = serial_config_layout.getHeight();
            }
        });

        final int[] heigth_tmp = {0, 0};
        final Context context = parent.getApplicationContext();
        final View myLayout = parent.getWindow().getDecorView();
        serial_control_layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                // r will be populated with the coordinates of your view that area still visible.
                serial_control_layout.getWindowVisibleDisplayFrame(r);
                int screenHeight = myLayout.getRootView().getHeight();
                int heightDiff = screenHeight - (r.bottom - r.top);
                if(heightDiff != heigth_tmp[0]){
                    heigth_tmp[0] = heightDiff;
                    if (heightDiff > 100) {
                        int statusBarHeight = 0;
                        try {
                            @SuppressLint("PrivateApi") Class<?> c = Class.forName("com.android.internal.R$dimen");
                            Object obj = c.newInstance();
                            Field field = c.getField("status_bar_height");
                            int x = Integer.parseInt(field.get(obj).toString());
                            statusBarHeight = context.getResources().getDimensionPixelSize(x);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        int realKeyboardHeight = heightDiff - statusBarHeight - 30;
                        heigth_tmp[1] = realKeyboardHeight;
                        if(!flag[0]) {
                            SetConfigLayout(config_layout_heigth, realKeyboardHeight, 500);
                        } else {
                            SetConfigLayout(0, realKeyboardHeight, 500);
                        }
                    }else if(heigth_tmp[1] != 0){
                        if(!flag[0]) {
                            SetConfigLayout(heigth_tmp[1], config_layout_heigth, 500);
                        } else {
                            SetConfigLayout(heigth_tmp[1], 0, 500);
                        }
                        heigth_tmp[1] = 0;
                    }
                }


            }
        });

        toggle_bt.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void onClick(View v) {
                if(!flag[0]) {
                    toggle_bt.setBackground(parent.getDrawable(R.drawable.iov_arrow_up));
                    flag[0] = true;
                    if(heigth_tmp[1] == 0)
                        SetConfigLayout(config_layout_heigth, 0, 500);
                } else {
                    toggle_bt.setBackground(parent.getDrawable(R.drawable.iov_arrow_down));
                    flag[0] = false;
                    if(heigth_tmp[1] == 0)
                        SetConfigLayout(0, config_layout_heigth, 500);
                }
            }
        });

        send_clean_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                send_input.setText("");
            }
        });

        send_bt.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.KITKAT)
            @Override
            public void onClick(View v) {
                if(myBluetoothClient.isConnected){
                    byte[] b_out;
                    byte[] b = get_send_data(send_input.getText().toString());
                    if(b.length < 20-3)
                    {
                        b_out = new byte[20];
                    }
                    else
                    {
                        b_out = new byte[b.length + 3];
                    }
                    b_out[0] = (byte) 0x82;
                    b_out[1] = (byte) (b.length+3);
                    b_out[2] = (byte) 0x01;
                    System.arraycopy(b, 0, b_out, 3, b.length);
                    myBluetoothClient.Write(b_out, b_out.length);
                    send_count += b.length;
                    send_count_label.setText("发送："+send_count);

                    if(show_send_check.isChecked()){
                        String s = "";
                        if(hex_send_check.isChecked()) {
                            String ss;
                            for(int i = 0; i < b.length; i++){
                                ss = Integer.toHexString(b[i]&0xff);
                                if(ss.length() == 1)
                                    ss = "0"+ss;
                                s += ss+" ";
                            }
                        }else{
                            s = new String(b, 0, b.length);
                        }
                        Log_send(s);
                    }
                } else {
                    Toast.makeText(parent, "串口未打开", Toast.LENGTH_SHORT).show();
                }
            }
        });

        bleScanCallback = new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
                String s = "", ss;
                for(int i = 0; i < scanRecord.length; i++){
                    ss = Integer.toHexString(scanRecord[i]&0xff);
                    if(ss.length() == 1)
                        ss = "0"+ss;
                    s += (ss + " ");
                }
                Log.i(TAG, "scanRecord:" + s);
                int i;
                for (i = 0; i < bluetoothDevices.size(); i++) {
                    if (mybluetoothDevices.get(i).mac_address.equals(device.getAddress())) {
                        mybluetoothDevices.get(i).device_name = device.getName();
                        mybluetoothDevices.get(i).rssi = rssi;
                        break;
                    }
                }
                if (i == bluetoothDevices.size()) {
                    bluetoothDevices.add(device);
                    mybluetoothDevices.add(new MyBluetoothDevice(device.getName(), device.getAddress(), rssi));
                }
                bluetoothDeviceAdapter.notifyDataSetChanged();
            }
        };

        open_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myBluetoothClient.handler = handler;
                myBluetoothClient.bluetoothDebuger = bluetoothDebuger;
                if(open_bt.getText().equals("发现设备")) {
                    //蓝牙链接
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        if (parent.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                            ActivityCompat.requestPermissions(parent, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
                        }
                    }
                    if (!bluetoothAdapter.isEnabled()) {
                        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                        parent.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
                    }
                    if(bluetoothAdapter.isEnabled())
                    {
//                        // Register the BroadcastReceiver
//                        IntentFilter filter = new IntentFilter();
//                        // filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//蓝牙开关状态
//                        // filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//蓝牙开始搜索
//                        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//蓝牙搜索结束
//                        filter.addAction(BluetoothDevice.ACTION_FOUND);//蓝牙发现新设备(未配对的设备)
//                        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); //BluetoothAdapter连接状态
//                        parent.registerReceiver(BluetoothScanReceiver, filter); // Don't forget to unregister during onDestroy
//                        bluetoothAdapter.startDiscovery();
                        bluetoothAdapter.startLeScan(bleScanCallback);
                        DevicePopWindow(v);
                    }
                } else {
                    //蓝牙断开
                    myBluetoothClient.Close();
                }
            }
        });

        clean_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Console_clear();
            }
        });

        pause_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(myBluetoothClient.isConnected){
                    if(pause_bt.getText().equals("继续")) {
                        console_pause = false;
                        pause_bt.setText("暂停");
                        status_label.setText("状态：已连接");
                    } else {
                        console_pause = true;
                        pause_bt.setText("继续");
                        status_label.setText("状态：已暂停");
                    }
                }
            }
        });

        kuaijie_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                InitPopWindow(v);
            }
        });

        auto_send_check.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(isChecked) {
                    auto_send_input.setEnabled(false);
                    if(myBluetoothClient.isConnected) {
                        new auto_send_thread().start();
                    }
                } else {
                    auto_send_input.setEnabled(true);
                    auto_send_flag = false;
                }
            }
        });

        send_input.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (send_input_flag) {
                    return;
                }
                send_input_flag = true;
                if (send_input_len > send_input.length())
                {
                    send_input_len = send_input.length();
                    send_input_flag = false;
                    return;
                }
                if (hex_send_check.isChecked()) {
                    if (send_input.length() > 0) {
                        send_input.setText(HexFormat(s.toString()));
                        send_input.setSelection(send_input.length());
                    }
                }
                send_input_len = send_input.length();
                send_input_flag = false;
            }

            @Override
            public void afterTextChanged(Editable s) {
            }
        });

        hex_send_check.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(isChecked){
                    if (send_input.length() > 0) {
                        send_input.setText(HexFormat(send_input.getText().toString()));
                        send_input.setSelection(send_input.length());
                    }
                }
            }
        });


        handler = new Handler(msg -> {
            String s;
            switch(msg.what){
                case ON_CONNECT:
                    open_bt.setText("关闭");
                    status_label.setText("状态：已连接");
                    if(auto_send_check.isChecked()) {
                        new auto_send_thread().start();
                    }
                    Log_i("已连接到"+myBluetoothClient.bluetoothDevice.getName()+"\n");
                    break;
                case ON_MESSAGE:
                    lock.lock();
                    console_text.setText(console_buf);
                    lock.unlock();
                    if(console_lock)
                        break;
                    console_lock = true;
                    console_scroll.post(new Runnable() {
                        @Override
                        public void run() {
                            console_scroll.fullScroll(View.FOCUS_DOWN);
                            console_lock = false;
                        }
                    });
                    break;
                case ON_SEND:
                    //send_count_label.setText("发送："+send_count);
                    break;
                case ON_CLOSE:
                    open_bt.setText("发现设备");
                    status_label.setText("状态：未连接");
                    Log_i("已关闭\n");
                    break;
                case ON_ERROR:
                    Log_i("内部错误，请重启再试\n");
                    break;
                case CONFIG_ERROR:
                    Log_i("串口配置错误\n");
                    break;
                case NOT_FOUND:
                    Log_i("未发现设备\n");
                    break;
                case NO_PERMISSION:
                    Log_i("未获取USB权限\n");
                    break;
                case UNSUPPORT:
                    Log_i("你的设备不支持蓝牙\n");
                    break;
                case CONSOLE_LOG:
                    s = (String) msg.obj;
                    lock.lock();
                    int start = console_buf.length();
                    if(console_buf.length() != 0)
                        console_buf.append("\n");
                    if(show_time_check.isChecked()) {
                        console_buf.append("[").append(simpleDateFormat.format(new Date(System.currentTimeMillis()))).append("]:\n");
                    }
                    console_buf.append(s);
                    ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.rgb(0, 255, 255));
                    console_buf.setSpan(foregroundColorSpan, start, console_buf.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
                    console_text.setText(console_buf);
                    lock.unlock();
                    console_scroll.post(new Runnable() {
                        @Override
                        public void run() {
                            console_scroll.fullScroll(View.FOCUS_DOWN);
                        }
                    });
                    break;
                case CONSOLE_REFRESH:
                    console_text.setText(console_buf);
                    send_count = 0;
                    recv_count = 0;
                    send_count_label.setText("发送：0");
                    recv_count_label.setText("接收：0");
                    break;
                default:
                    break;
            }
            return false;
        });

    }

    @SuppressLint("SetTextI18n")
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    public byte[] get_send_data(String s){
        if(!s.equals(""))
        {
            byte[] b;
            if(hex_send_check.isChecked()) {
                int i = 0, start_index = 0;
                String[] ss = send_input.getText().toString().split(" ");
                b = new byte[ss.length];
                for(i = 0; i < ss.length; i++){
                    b[i] = (byte) Integer.parseInt(ss[i], 16);
                }
                s = start_index_input.getText().toString();
                if(s.equals("")){
                    start_index = 0;
                }else{
                    start_index = Integer.parseInt(s);
                }
                if(send_parity_check.isChecked()){
                    b = send_parity(b, start_index, b.length-start_index);
                }
            }else{
                if(send_newline_check.isChecked()){
                    s += "\r\n";
                }
                b = s.getBytes(StandardCharsets.UTF_8);
            }
            return b;
        }
        return null;
    }

    public byte[] send_parity(byte[] b, int offset, int len)
    {
        byte[] data;
        int parity_index = send_parity_spinner.getSelectedItemPosition();
        switch(parity_index){
            case 0: //CRC16
                data = new byte[b.length+2];
                System.arraycopy(b, 0, data, 0, b.length);
                int res = CRC_Calculate.getCRC16(b, offset, len);
                data[b.length] = (byte)(res & 0xff);
                data[b.length+1] = (byte)((res>>8) & 0xff);
                return data;
            case 1: //CRC32
                data = new byte[b.length+4];
                System.arraycopy(b, 0, data, 0, b.length);
                long res32 = CRC_Calculate.getCRC32(b, offset, len);
                data[b.length] = (byte)(res32 & 0xff);
                data[b.length+1] = (byte)((res32>>8) & 0xff);
                data[b.length+2] = (byte)((res32>>16) & 0xff);
                data[b.length+3] = (byte)((res32>>24) & 0xff);
                return data;
            case 2: //CRC8
                data = new byte[b.length+1];
                System.arraycopy(b, 0, data, 0, b.length);
                data[b.length] = CRC_Calculate.getCRC8(b, offset, len);
                return data;
            case 3: //SUM
                data = new byte[b.length+1];
                System.arraycopy(b, 0, data, 0, b.length);
                data[b.length] = CRC_Calculate.SumCheck(b, offset, len);
                return data;
            default:
                return b;
        }
    }

    class auto_send_thread extends Thread{
        @SuppressLint("SetTextI18n")
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        @Override
        public void run() {
            int period = Integer.parseInt(auto_send_input.getText().toString());
            if(period < 10)
                period = 10;
            String s;
            auto_send_flag = true;
            byte[] b;
            while(myBluetoothClient.isConnected && auto_send_flag) {
                try {
                    if(send_input.getText().length() > 0)
                    {
                        b = get_send_data(send_input.getText().toString());
                        myBluetoothClient.Write(b, b.length);
                        send_count += b.length;
                        send_count_label.setText("发送："+send_count);
                        Thread.sleep(period);
                    }
                    else
                    {
                        Thread.sleep(500);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Log_i(e.toString());
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException interruptedException) {
                        interruptedException.printStackTrace();
                    }
                }
            }
        }
    }

    private void SetConfigLayout(int from, int to, int time) {
        TypeEvaluator<ViewGroup.LayoutParams> evaluator = new HeightEvaluator();
        ViewGroup.LayoutParams start = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, from);
        ViewGroup.LayoutParams end = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, to);
        ValueAnimator animator = ObjectAnimator.ofObject(serial_config_layout, "layoutParams", evaluator, start, end);
        AnimatorSet set = new AnimatorSet();
        set.play(animator);
        set.setDuration(time);
        set.start();
    }
    class HeightEvaluator implements TypeEvaluator<ViewGroup.LayoutParams> {
        @Override
        public ViewGroup.LayoutParams evaluate(float fraction, ViewGroup.LayoutParams startValue, ViewGroup.LayoutParams endValue) {
            ViewGroup.LayoutParams params = serial_config_layout.getLayoutParams();
            params.height = (int) (startValue.height + fraction * (endValue.height - startValue.height));
            return params;
        }
    }


    @SuppressLint("ClickableViewAccessibility")
    private void DevicePopWindow(View v) {
        View device_view = LayoutInflater.from(parent).inflate(R.layout.device_window, null, false);
        ListView listView = (ListView) device_view.findViewById(R.id.device_list);
        //1.构造一个PopupWindow，参数依次是加载的View，宽高
        PopupWindow popWindow = new PopupWindow(device_view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        popWindow.setAnimationStyle(R.style.popupAnimation);  //设置加载动画
        popWindow.setTouchable(true);
        popWindow.setTouchInterceptor(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return false;
            }
        });
        popWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));    //要为popWindow设置一个背景才有效
        popWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                bluetoothAdapter.stopLeScan(bleScanCallback);
                Log.i(TAG, "--bluetoothAdapter.stopLeScan");
                //
                // parent.unregisterReceiver(BluetoothScanReceiver);
                bluetoothDevices.clear();
                mybluetoothDevices.clear();
                //popWindow.dismiss();
                WindowManager.LayoutParams lp = parent.getWindow().getAttributes();
                parent.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
                lp.alpha = 1f;
                parent.getWindow().setAttributes(lp);
            }
        });

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent1, View view, int position, long id) {
                myBluetoothClient.Connect(bluetoothDevices.get(position));
                Toast.makeText(parent, "you click "+mybluetoothDevices.get(position).device_name, Toast.LENGTH_SHORT).show();
                //handler.sendEmptyMessage(ON_CONNECT);
                popWindow.dismiss();
            }
        });

        listView.setAdapter(bluetoothDeviceAdapter);
        //popWindow.showAsDropDown(serial_view, 50, 50);
        popWindow.showAtLocation(bluetooth_view, Gravity.CENTER, 0, 0);
        WindowManager.LayoutParams lp = parent.getWindow().getAttributes();
        parent.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        lp.alpha = 0.3f;
        parent.getWindow().setAttributes(lp);
    }

    @SuppressLint("ClickableViewAccessibility")
    private void InitPopWindow(View v) {
        View kuaihie_view = LayoutInflater.from(parent).inflate(R.layout.kuaijie_window, null, false);
        ListView listView = (ListView) kuaihie_view.findViewById(R.id.kuaijie_list);
        ImageButton kuaijie_add_bt = kuaihie_view.findViewById(R.id.kuaijie_add_bt);
        EditText kuaijie_input = kuaihie_view.findViewById(R.id.kuaijie_input);
        EditText kuaijie_name_input = kuaihie_view.findViewById(R.id.kuaijie_name_input);
        //1.构造一个PopupWindow，参数依次是加载的View，宽高
        PopupWindow popWindow = new PopupWindow(kuaihie_view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        popWindow.setAnimationStyle(R.style.popupAnimation);  //设置加载动画
        popWindow.setTouchable(true);
        popWindow.setTouchInterceptor(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return false;
            }
        });
        popWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));    //要为popWindow设置一个背景才有效
        popWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                //popWindow.dismiss();
                WindowManager.LayoutParams lp = parent.getWindow().getAttributes();
                parent.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
                lp.alpha = 1f;
                parent.getWindow().setAttributes(lp);
            }
        });
        KuaijieTextAdapter textAdapter = new KuaijieTextAdapter(kuaijie_data, parent);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                send_input.append(kuaijie_data.get(position).content);
                popWindow.dismiss();
            }
        });

        final float[] register_on_click_x = {0};
        listView.setOnTouchListener(new View.OnTouchListener() {
            @SuppressLint("ClickableViewAccessibility")
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                register_on_click_x[0] = event.getX();
                return false;
            }
        });

        listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent1, View view1, int position, long id) {
                View delete_view = LayoutInflater.from(parent).inflate(R.layout.kuaijie_delete_layout, null, false);
                Button kuaijie_delete_bt = (Button) delete_view.findViewById(R.id.kuaijie_delete_bt);
                //1.构造一个PopupWindow，参数依次是加载的View，宽高
                PopupWindow popWindow2 = new PopupWindow(delete_view,
                        ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
                popWindow2.setTouchable(true);
                popWindow2.setTouchInterceptor(new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, MotionEvent event) {
                        return false;
                    }
                });
                popWindow2.setBackgroundDrawable(new ColorDrawable(0x00000000));
                popWindow2.showAsDropDown(view1, (int)register_on_click_x[0]-200, 0);
                kuaijie_delete_bt.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        MyApp.myDBHelper.kuaijie_delete(kuaijie_data.get(position).content);
                        kuaijie_data.remove(position);
                        textAdapter.notifyDataSetChanged();
                        popWindow2.dismiss();
                    }
                });
                return true;
            }
        });
        listView.setAdapter(textAdapter);
        kuaijie_add_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(kuaijie_input.length() > 0){
                    String s = kuaijie_input.getText().toString();
                    String ss = kuaijie_name_input.getText().toString();
                    boolean isExist = false;
                    for(KuaijieText text : kuaijie_data){
                        if(text.content.equals(s)){
                            isExist = true;
                        }
                    }
                    if(!isExist){
                        kuaijie_data.add(0, new KuaijieText(ss, s));
                        MyApp.myDBHelper.kuaijie_insert(ss,s);
                        textAdapter.notifyDataSetChanged();
                    } else {
                        Toast.makeText(parent, "文本已存在", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
        //popWindow.showAsDropDown(serial_view, 50, 50);
        popWindow.showAtLocation(bluetooth_view, Gravity.CENTER, 0, 0);
        WindowManager.LayoutParams lp = parent.getWindow().getAttributes();
        parent.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        lp.alpha = 0.3f;
        parent.getWindow().setAttributes(lp);
    }

    public void Log_i(String s) {
        Message msg = new Message();
        msg.what = CONSOLE_LOG;
        msg.obj = s;
        handler.sendMessage(msg);
    }

    private void Log_send(String s) {
        if(console_pause){
            return;
        }
        lock.lock();
        int start = console_buf.length();
        if (auto_newline_check.isChecked() && !show_time_check.isChecked()) {
            if (console_buf.length() != 0)
                console_buf.append("\n");
        }
        if(show_time_check.isChecked()) {
            console_buf.append("\n[").append(simpleDateFormat.format(new Date(System.currentTimeMillis()))).append("]:\n");
        }
        console_buf.append(s);
        ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.YELLOW);
        console_buf.setSpan(foregroundColorSpan, start, console_buf.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        console_text.setText(console_buf);
        lock.unlock();
        console_scroll.post(new Runnable() {
            @Override
            public void run() {
                console_scroll.fullScroll(View.FOCUS_DOWN);
                console_lock = false;
            }
        });
    }

    @SuppressLint("SetTextI18n")
    public void Log_recv(byte[] buf, int recv_len) {
        recv_count += recv_len;
        recv_count_label.setText("接收："+recv_count);
        if(console_pause)
            return;

        lock.lock();
        if(console_buf.length() > 6000){
            console_buf = new SpannableStringBuilder();
            //console_buf.delete(0, 5000);
        }
        int start = console_buf.length();
        if (auto_newline_check.isChecked() && !show_time_check.isChecked()) {
            if (console_buf.length() != 0)
                console_buf.append("\n");
        }
        if (show_time_check.isChecked()) {
            console_buf.append("\n[").append(simpleDateFormat.format(new Date(System.currentTimeMillis()))).append("]:\n");
        }
        StringBuilder s = new StringBuilder();
        if(hex_recv_check.isChecked()){
            String ss;
            for(int i = 0; i < recv_len; i++){
                ss = Integer.toHexString(buf[i]&0xff);
                if(ss.length() == 1)
                    ss = "0"+ss;
                s.append(ss).append(" ");
            }
        }else{
            s = new StringBuilder(new String(buf, 0, recv_len));
        }
        console_buf.append(s.toString());
        ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.WHITE);
        console_buf.setSpan(foregroundColorSpan, start, console_buf.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        handler.sendEmptyMessage(ON_MESSAGE);
        lock.unlock();
    }

    public void Console_clear()
    {
        lock.lock();
        console_buf = new SpannableStringBuilder();
        lock.unlock();
        handler.sendEmptyMessage(CONSOLE_REFRESH);
    }

    public boolean IsHexadecimal(String str)
    {
        final String PATTERN = "0123456789abcdefABCDEF";
        return PATTERN.contains(str);
    }

    private String HexFormat (String s)
    {
        s = s.replace(" ", "");
        String ss;
        StringBuilder res = new StringBuilder();
        for(int i = 0; i < s.length(); i++)
        {
            ss = s.substring(i, i+1);
            if (IsHexadecimal(ss))
            {
                res.append(ss);
                if((i % 2) == 1)
                {
                    res.append(" ");
                }
            }
        }
        return res.toString();
    }
}
